#include <stdint.h>
#include <stdio.h>
#include "stdlib.h"
#include "betterkey.h"

#define SHORT_PRESS_TIME 50   // 单击时间阈值，单位为毫秒
#define MULTI_CLICK_TIME 300  // 多击时间间隔，单位为毫秒
#define LONG_PRESS_TIME 800   // 长按时间阈值，单位为毫秒
#define LONG_HOLD_TIME_MAX 2000  // 长按保持时间阈值，单位为毫秒
#define LONG_PRESS_RELEASE_TIME 500  // 长按与长按保持的时间间隔
#define LONG_HOLD_INTERVAL 200
#define MAX_CLICK_COUNT 5  // 最大点击次数

// 按键事件结构体
typedef struct key_event_t {
    int id;                    // 按键ID
    enum key_status status;    // 按键状态
    uint32_t press_time;       // 按下时间
    uint32_t release_time;     // 松开时间
    uint16_t click_count;      // 点击次数
    uint16_t hold_count;       // 长按保持次数
    struct key_event_t *next;  // 下一个按键事件
} key_event_t;

static key_event_t *head = NULL;
static time_get_callback global_time_get = NULL;
static key_value_get_callback global_key_value_get = NULL;

int key_event_init(time_get_callback time_get, key_value_get_callback key_value_get) {
    if (time_get == NULL || key_value_get == NULL) {
        return -1;
    }
    global_time_get = time_get;
    global_key_value_get = key_value_get;
    return 0;
}

static void deleteMyKey(uint32_t id){
    if(head == NULL) return;
    
    struct key_event_t *p = head;
    struct key_event_t *pre = NULL;
    
    while(p != NULL){
        if(p->id == id){
            if(pre == NULL){
                head = p->next;
            }else{
                pre->next = p->next;
            }
            free(p);
            return;
        }
        pre = p;
        p = p->next;
    }
}

static void addMyKey(uint32_t id){
    struct key_event_t *new = (struct key_event_t *)malloc(sizeof(struct key_event_t));
    if(new == NULL){
        return;
    }
    new->id = id;
    new->press_time = 0;
    new->release_time = 0;
    new->hold_count = 0;
    new->status = OFF;
    new->next = NULL;
    
    if(head == NULL){
        head = new;
    }else{
        struct key_event_t *p = head;
        while(p->next != NULL){
            p = p->next;
        }
        p->next = new;
    }
}

key_event_t* findMyKey(int id)
{
    key_event_t *current = head;
    while(current != NULL && current->id != id)
    {
        current = current->next;
    }
    return current;
}

uint16_t Key_GetClickCount(int id)
{
    key_event_t*p=findMyKey(id);
    if(p == NULL) {
        return 0; // 如果没有找到按键事件，返回0
    }
    else{
        return p->click_count; // 返回点击次数
    }
}

/* 按键状态转换函数
 * 功能：根据按键ID和当前状态，计算并返回新的按键状态
 * 参数：id - 按键标识符
 * 返回值：enum key_status - 当前按键的最新状态
 * 状态机说明：
 *   OFF         : 初始状态/释放状态
 *   WAITING     : 按键按下但未达长按阈值
 *   CLICK       : 单击完成（按下后释放）
 *   MULTI_CLICK : 多击进行中（双击/三击等）
 *   LONG_PRESS  : 长按触发（超过长按时间阈值）
 *   LONG_HOLD   : 长按保持（持续按住时周期性触发）
 * 全局依赖：
 *   global_time_get      : 获取系统时间戳（毫秒级）
 *   global_key_value_get : 获取按键物理状态（KEY_ON/KEY_OFF）
 * 时间常量说明：
 *   LONG_PRESS_TIME     : 长按触发阈值（如500ms）
 *   MULTI_CLICK_TIME    : 多击时间窗口（如300ms）
 *   LONG_HOLD_INTERVAL  : 长按保持触发间隔（如1000ms）
 */
enum key_status Key_StatusChange(int id) {
    // 全局函数指针校验（防止未初始化导致崩溃）
    if (global_time_get == NULL || global_key_value_get == NULL) {
        return OFF;
    }
    
    // 按键事件对象管理
    key_event_t *p = findMyKey(id);       // 查找按键状态记录
    if (p == NULL) {                       // 首次检测到此按键
        addMyKey(id);                      // 创建新记录
        p = findMyKey(id);                 // 重新获取指针
        if (p == NULL) {                   // 创建失败处理
            return OFF;
        }
    }
    
    // 当前状态快照（避免多次调用全局函数）
    uint32_t current_time = global_time_get();
    enum key_value current_value = global_key_value_get(id);
    enum key_status status = p->status;    // 上次保存的状态
    uint32_t elapsed_time;                 // 时间差临时计算
    uint32_t press_elapsed = current_time - p->press_time; // 当前按下持续时间
    
    // 状态跃迁检测：从OFF到WAITING（立即响应新按下事件）
    if (current_value == KEY_ON && status == OFF) {
        p->press_time = current_time;      // 记录按下时刻
        p->click_count = 0;                // 重置点击计数
        p->release_time = 0;               // 清除释放时间
        p->status = WAITING;               // 进入等待状态
        return WAITING;                    // 立即返回新状态
    }
    
    // 状态机核心处理（基于当前状态分支）
    switch (status) {
        case OFF:
            // OFF状态下检测到按下：初始化参数并进入等待状态
            if (current_value == KEY_ON) {
                p->press_time = current_time;
                p->click_count = 0;
                p->release_time = 0;
                p->status = WAITING;
                return WAITING;
            }
            break;
            
        case WAITING:
            /* 等待状态处理逻辑：
             * 1. 若释放：记录释放时间，标记为单击（click_count=1）
             * 2. 若持续按下且超长按阈值：进入长按状态
             * 注意：未满足条件时保持WAITING状态
             */
            if (current_value == KEY_OFF) {
                p->release_time = current_time;
                p->click_count = 1;        // 首次单击计数
                p->status = CLICK;
                return CLICK;
            } 
            else if (press_elapsed >= LONG_PRESS_TIME) {
                p->status = LONG_PRESS;     // 触发长按
                p->hold_count = 0;          // 初始化长按保持计数
                return LONG_PRESS;
            }
            return WAITING;                 // 未达条件，保持等待
            break;
            
        case CLICK:
            /* 单击完成后的处理：
             * 1. 若再次按下：检测是否在多击时间窗内
             *   是 → 进入多击状态（增加点击计数）
             *   否 → 返回单击状态并重置为OFF
             * 2. 若超多击时间窗：自动重置为OFF状态
             */
            if (current_value == KEY_ON) {
                elapsed_time = current_time - p->release_time;
                if (elapsed_time <= MULTI_CLICK_TIME) {
                    p->status = MULTI_CLICK;
                    p->click_count++;       // 增加点击计数（双击/三击）
                    p->press_time = current_time;
                    p->release_time = 0;    // 重置释放时间（因再次按下）
                    p->hold_count = 0;
                    return MULTI_CLICK;
                } 
                else {                      // 超过多击时间窗
                    p->status = OFF;        // 结束单击周期
                    return CLICK;           // 仍返回本次单击
                }
            } 
            else if (current_time - p->release_time > MULTI_CLICK_TIME) {
                p->status = OFF;            // 超时自动重置
                return CLICK;
            }
            return CLICK;                   // 保持单击状态
            break;
            
        case MULTI_CLICK:
            /* 多击状态处理：
             * 释放时：
             *   - 若按下时间超窗：退出多击状态（判定为无效多击）
             * 按下时：
             *   - 若超长按阈值：转长按状态
             *   - 若在时间窗内：增加点击计数（等待下一次释放）
             */
            if (current_value == KEY_OFF) {
                p->release_time = current_time;
                // 释放时检测：若本次按下时间过长，判定多击失败
                if (current_time - p->press_time > MULTI_CLICK_TIME) {
                    p->status = OFF;        // 退出多击状态
                    p->click_count = 0;     // 重置计数
                    p->hold_count = 0;
                    return OFF;
                }
                return MULTI_CLICK;
            } 
            else {
                // 按下持续期间检测长按
                if (press_elapsed >= LONG_PRESS_TIME ) {
                    p->status = LONG_PRESS; // 转长按状态（覆盖多击）
                    p->hold_count = 0;
                    return LONG_PRESS;
                }
                // 快速连按检测：在上次释放后规定时间内再次按下
                if (p->release_time > 0 && p->click_count < MAX_CLICK_COUNT) {  // 存在前次释放记录
                    elapsed_time = current_time - p->release_time;
                    if (elapsed_time <= MULTI_CLICK_TIME) {
                        p->click_count++;   // 增加有效点击计数
                        p->press_time = current_time;
                        p->release_time = 0; // 清除释放标记（因再次按下）
                    }
                }
                return MULTI_CLICK;
            }
            break;
            
        case LONG_PRESS:
            /* 长按状态处理：
             * 释放 → 立即返回OFF
             * 持续按下 → 检测是否达到保持触发间隔
             */
            if (current_value == KEY_OFF) {
                p->status = OFF;            // 释放即重置
                return OFF;
            } 
            else {
                elapsed_time = press_elapsed - LONG_PRESS_TIME;
                // 达到长按保持间隔：升级为LONG_HOLD状态
                if (elapsed_time >= LONG_HOLD_INTERVAL) {
                    p->status = LONG_HOLD;
                    p->hold_count = 1;      // 初始化保持计数
                    return LONG_HOLD;
                }
            }
            return LONG_PRESS;              // 保持长按状态
            break;
            
        case LONG_HOLD:
            /* 长按保持状态：
             * 释放 → 重置为OFF
             * 持续按下 → 按保持间隔周期性触发
             */
            if (current_value == KEY_OFF) {
                p->status = OFF;
            } 
            else {
                elapsed_time = press_elapsed - LONG_PRESS_TIME;
                // 周期性触发：每达到整数倍间隔时更新计数
                if (elapsed_time >= (p->hold_count + 1) * LONG_HOLD_INTERVAL) {
                    p->hold_count++;        // 增加保持计数
                    return LONG_HOLD;        // 触发新事件
                }
            }
            return LONG_HOLD;               // 无事件时保持状态
            break;
    }
    
    return OFF; // 默认返回OFF状态（异常处理）
}